/**
 * @author luguoxiang
 * @date 2022/7/5
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import { computed, defineAsyncComponent, ref } from 'vue';
import { ChevronDownIcon, ChevronRightIcon, LoadingIcon } from 'tdesign-icons-vue-next';
import { Arrayable, chooseFile, copyToClipboard, message, notEmpty, toPromise } from '@/soar';
import { LgTableProps } from '../types';

export const LgTable = defineAsyncComponent(() => import('./Table.vue'));

/**
 * @author luguoxiang
 * @date 2022/7/5
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
type Api = {
  query?(params: any): any;
  remove?(ids: Arrayable<string | number>): Promise<any>;
  exports?(params: any): Promise<any>;
  imports?(file: File): Promise<any>;
};

export interface UseTableOptions<T> {
  rowKey?: string;
  api?: Api | any;
  props?: LgTableProps<T>;
  onMounted?(e: any): void;
}

export interface UseTreeTableOptions<T> extends UseTableOptions<T> {
  loadChildren(p: { row: any; params: any }): any[] | Promise<any[]>;
  handleChildren?(row: any): any;
  tree?: Object;
}

/**
 * 点击单元格复制内容事件
 * @param col
 * @param row
 * @param e
 */
export function onCellClickCopy({ col, row, e }) {
  try {
    // @ts-ignore 点击单元格复制内容
    const text = window.getSelection().toString() || e.target?.innerText;
    if (col.colKey in row && text) {
      copyToClipboard(text).then(() => {
        message.info('内容已复制');
      });
    }
  } catch (e) {
    console.error(e);
  }
}

/**
 * 使用表格
 * @param options
 */
export function useTable<T>(options: UseTableOptions<T> = {}) {
  const { rowKey = 'id', props = {}, api = {} } = options;
  const { fields = [rowKey] } = props;

  let table: any = null;

  /**
   * 清空选择
   */
  function clearSelection() {
    table.clearSelection();
  }

  /**
   * 清空选择
   */
  function getSelectRows() {
    return table?.selectedRows;
  }

  /**
   * 清空选择
   */
  function getSelectRowKeys() {
    return table?.selectedKeys;
  }

  /**
   * 导出
   */
  function exports() {
    message.confirm('确定导出所筛选的数据吗？').then(() => {
      const ids = getSelectRowKeys();
      const $soarQuery = table.getSoarQuery();
      if (ids && ids.length) {
        $soarQuery[`${rowKey || 'id'}-in`] = ids;
      }
      api.exports({ $soarQuery });
    });
  }

  /**
   * 导入
   */
  function imports() {
    chooseFile({ accept: '.xls,.xlsx' }).then((files) => api.imports(files[0]));
  }

  /**
   * 重新加载
   * @param pageNo 页码
   */
  function reload(pageNo?: number) {
    table.reload(pageNo);
  }

  /**
   * 操作成功时
   * @param pageNo
   */
  function success() {
    clearSelection();
    reload();
  }

  /**
   * 单个处理
   * @param msg
   * @param handler 处理函数
   */
  function handleSingle(msg: string, handler: Function) {
    message.confirm(msg).then(() => {
      handler()?.then?.(success);
    });
  }

  /**
   * 批量处理
   * @param msg
   * @param handler
   * @param id
   */
  function handleBatch(msg: Function, handler: Function, id?: string | number) {
    const ids = id ? [id] : getSelectRowKeys();
    notEmpty(ids, '请选择至少一条数据');
    message.confirm(msg(ids)).then(() => {
      handler(ids)?.then?.(success);
    });
  }

  /**
   * 删除方法
   * @param id
   */
  function remove(id?: string | number) {
    handleBatch(
      (ids: string | any[]) => `将要删除${ids.length}条记录`,
      (ids: any) => api.remove(ids),
      id,
    );
  }

  const tableRef = ref();
  const tableProps = ref<LgTableProps<T>>({
    data: api.query,
    rowKey,
    fields,
    // 合并配置
    searchbar: {
      autoTrim: true,
    },
    selection: true,
    index: true,
    actionbar: true,
    pagination: true,
    ...props,
    ref(e) {
      table = e;
      tableRef.value = e;
      options.onMounted?.(e);
    },
  });

  const selectedKeys = computed<string | number>(() => tableRef.value?.selectedKeys ?? []);
  const selectedRows = computed<T>(() => tableRef.value?.selectedRows ?? []);

  return {
    tableProps,
    tableRef,
    selectedKeys,
    selectedRows,
    success,
    reload,
    clearSelection,
    getSelectRows,
    getSelectRowKeys,
    handleSingle,
    handleBatch,
    remove,
    exports,
    imports,
  };
}

/**
 * 使用树形表格
 * @param options
 */
export function useTreeTable<T>(options: UseTreeTableOptions<T>) {
  const {
    tree = {},
    loadChildren,
    handleChildren = (x) => {
      x.children ??= x.descendantQuantity > 0;
      return x;
    },
  } = options;
  const ex = useTable(options);
  const { tableProps, tableRef } = ex;

  const loadingStatus = {};
  // @ts-ignore
  tableProps.value.dataHandle ??= (res) => {
    res.list.forEach((x) => (x.children = x.descendantQuantity > 0));
  };
  // @ts-ignore
  tableProps.value.tableProps = {
    tree: {
      childrenKey: 'children',
      treeNodeColumnIndex: 2,
      ...tree,
    },
    // @ts-ignore
    treeExpandAndFoldIcon(h, { type, rowIndex }) {
      // eslint-disable-next-line no-nested-ternary
      return h(type === 'expand' ? (loadingStatus[rowIndex] ? LoadingIcon : ChevronRightIcon) : ChevronDownIcon);
    },
    onTreeExpandChange({ row, rowIndex }) {
      // @ts-ignore
      if (row.children === true) {
        toPromise(loadChildren({ row, params: tableRef.value.getParams() }))
          .then((res) => {
            if (typeof tableProps.value.dataHandle === 'function') {
              const d = tableProps.value.dataHandle(res);
              if (d) {
                res = d;
              }
            }
            if (Array.isArray(res)) {
              res = { list: res };
            }
            if (res.list.length) {
              tableRef.value.tableRef.appendTo(row[this.rowKey], res.list);
            } else {
              delete row.children;
            }
          })
          .finally(() => {
            delete loadingStatus[rowIndex];
          });
        loadingStatus[rowIndex] = true;
      } else {
        delete loadingStatus[rowIndex];
      }
    },
    ...tableProps.value.tableProps,
  };

  return {
    ...ex,
    tableProps,
  };
}

export default LgTable;
